package vn.bus.auxiliary;

import vn.bus.dto.LabelDTO;

import java.util.ArrayList;

public class MinHeap {

	private ArrayList<LabelDTO> LLVTemporary = new ArrayList<LabelDTO>();

	// OK
	public LabelDTO getMinLLVTemp() {
		if (isEmpty())
			return null;
		else
			return LLVTemporary.get(0);
	}

	// OK
	public boolean isEmpty() {
		return LLVTemporary.size() == 0 ? true : false;
	}

	// OK
	public void insert(LabelDTO LTemp, ArrayList<String> Priority) {
		LLVTemporary.add(LTemp);
		bubbleUp(LLVTemporary.size() - 1, Priority);
	}

	// OK
	private void bubbleUp(int nodeIndex, ArrayList<String> Priority) {
		int parentIndex;
		LabelDTO Ltemp;
		if (nodeIndex != 0) {
			parentIndex = (nodeIndex - 1) / 2;
			if (Compare(parentIndex, nodeIndex, Priority) == "second") {
				Ltemp = LLVTemporary.get(parentIndex);
				LLVTemporary.set(parentIndex, LLVTemporary.get(nodeIndex));
				LLVTemporary.set(nodeIndex, Ltemp);
				bubbleUp(parentIndex, Priority);
			}
		}
	}

	// OK
	public void removeMin(ArrayList<String> Priority) {
		if (!isEmpty()) {
			LLVTemporary.set(0, LLVTemporary.get(LLVTemporary.size() - 1));
			LLVTemporary.remove(LLVTemporary.size() - 1);
			if (LLVTemporary.size() > 0) {
				sinkDown(0, Priority);
			}
		}
	}

	// OK
	private void sinkDown(int nodeIndex, ArrayList<String> Priority) {
		LabelDTO Ltemp;
		int leftChildIndex, rightChildIndex, minIndex;
		leftChildIndex = 2 * nodeIndex + 1;
		rightChildIndex = 2 * nodeIndex + 2;
		if (rightChildIndex >= LLVTemporary.size()) {
			if (leftChildIndex >= LLVTemporary.size())
				return;
			else
				minIndex = leftChildIndex;
		} else {
			if (Compare(leftChildIndex, rightChildIndex, Priority) == "first") {
				minIndex = leftChildIndex;
			} else {
				minIndex = rightChildIndex;
			}
		}
		if (Compare(nodeIndex, minIndex, Priority) == "second") {
			Ltemp = LLVTemporary.get(minIndex);
			LLVTemporary.set(minIndex, LLVTemporary.get(nodeIndex));
			LLVTemporary.set(nodeIndex, Ltemp);
			sinkDown(minIndex, Priority);
		}
	}

	// Compare
	private String Compare(int fIndex, int sIndex, ArrayList<String> Priority) {
		LabelDTO LP1 = new LabelDTO();
		LabelDTO LP2 = new LabelDTO();
		LP1 = LLVTemporary.get(fIndex);
		LP2 = LLVTemporary.get(sIndex);
		int[] arrOne = new int[3], arrTwo = new int[3];
		arrOne[0] = LP1.getT();
		arrOne[1] = LP1.getD();
		arrOne[2] = LP1.getP();
		arrTwo[0] = LP2.getT();
		arrTwo[1] = LP2.getD();
		arrTwo[2] = LP2.getP();
		switch (Priority.size()) {
		case 1:
			return compareOnePriority(arrOne, arrTwo, Priority);
		case 2:
			return compareTwoPriority(arrOne, arrTwo, Priority);
		case 3:
			return compareThreePriority(arrOne, arrTwo, Priority);
		}
		return "first";
	}

	// OK
	private String compareOnePriority(int[] arrOne, int[] arrTwo, ArrayList<String> Priority) {
		switch (Priority.get(0)) {
		case "st":
			if (arrOne[0] > arrTwo[0]) {
				return "second";
			} else
				return "first";
		case "sd":
			if (arrOne[1] > arrTwo[1]) {
				return "second";
			} else
				return "first";
		case "sp":
			if (arrOne[2] > arrTwo[2]) {
				return "second";
			} else
				return "first";
		}
		// NOTE
		return "first";
	}

	private String compareTwoPriority(int[] arrOne, int[] arrTwo, ArrayList<String> Priority) {
		switch (Priority.get(0)) {
		case "st":
			if (arrOne[0] > arrTwo[0]) {
				return "second";
			} else if (arrOne[0] < arrTwo[0]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "sd":
					if (arrOne[1] > arrTwo[1]) {
						return "second";
					} else {
						return "first";
					}
				case "sp":
					if (arrOne[2] > arrTwo[2]) {
						return "second";
					} else {
						return "first";
					}
				}
			}
			break;
		case "sd":
			if (arrOne[1] > arrTwo[1]) {
				return "second";
			} else if (arrOne[1] < arrTwo[1]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "st":
					if (arrOne[0] > arrTwo[0]) {
						return "second";
					} else {
						return "first";
					}
				case "sp":
					if (arrOne[2] > arrTwo[2]) {
						return "second";
					} else {
						return "first";
					}
				}
			}
			break;
		case "sp":
			if (arrOne[2] > arrTwo[2]) {
				return "second";
			} else if (arrOne[2] < arrTwo[2]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "st":
					if (arrOne[0] > arrTwo[0]) {
						return "second";
					} else {
						return "first";
					}
				case "sd":
					if (arrOne[1] > arrTwo[1]) {
						return "second";
					} else {
						return "first";
					}
				}
			}
			break;
		}
		return "first";
	}

	private String compareThreePriority(int[] arrOne, int[] arrTwo, ArrayList<String> Priority) {
		switch (Priority.get(0)) {
		case "st":
			if (arrOne[0] > arrTwo[0]) {
				return "second";
			} else if (arrOne[0] < arrTwo[0]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "sd":
					if (arrOne[1] > arrTwo[1]) {
						return "second";
					} else if (arrOne[1] < arrTwo[1]) {
						return "first";
					} else {
						if (arrOne[2] > arrTwo[2]) {
							return "second";
						} else {
							return "first";
						}
					}
				case "sp":
					if (arrOne[2] > arrTwo[2]) {
						return "second";
					} else if (arrOne[2] < arrTwo[2]) {
						return "first";
					} else {
						if (arrOne[1] > arrTwo[1]) {
							return "second";
						} else {
							return "first";
						}
					}
				}
			}
			break;
		case "sd":
			if (arrOne[1] > arrTwo[1]) {
				return "second";
			} else if (arrOne[1] < arrTwo[1]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "st":
					if (arrOne[0] > arrTwo[0]) {
						return "second";
					} else if (arrOne[0] < arrTwo[0]) {
						return "first";
					} else {
						if (arrOne[2] > arrTwo[2]) {
							return "second";
						} else {
							return "first";
						}
					}
				case "sp":
					if (arrOne[2] > arrTwo[2]) {
						return "second";
					} else if (arrOne[2] < arrTwo[2]) {
						return "first";
					} else {
						if (arrOne[0] > arrTwo[0]) {
							return "second";
						} else {
							return "first";
						}
					}
				}
			}
			break;
		case "sp":
			if (arrOne[2] > arrTwo[2]) {
				return "second";
			} else if (arrOne[2] < arrTwo[2]) {
				return "first";
			} else {
				switch (Priority.get(1)) {
				case "st":
					if (arrOne[0] > arrTwo[0]) {
						return "second";
					} else if (arrOne[0] < arrTwo[0]) {
						return "first";
					} else {
						if (arrOne[1] > arrTwo[1]) {
							return "second";
						} else {
							return "first";
						}
					}
				case "sd":
					if (arrOne[1] > arrTwo[1]) {
						return "second";
					} else if (arrOne[1] < arrTwo[1]) {
						return "first";
					} else {
						if (arrOne[0] > arrTwo[0]) {
							return "second";
						} else {
							return "first";
						}
					}
				}
			}
			break;
		}
		return "first";
	}
}